using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.Outlook;
using TeamXpandLicence.ObjectExchange;
using TXLooker.Common;
using TXLooker.Common.Core;
using Exception = System.Exception;
using MAPIFolder = Microsoft.Office.Interop.Outlook.MAPIFolder;

namespace TXLooker.Core
{
    internal class ExtentionDataProvider: IExtentionDataProvider
    {
        // Fields
        private OutlookDataProvider m_olDataProvider;
        private TFEventHandler<IEnumerable<IServerProvider>> m_OnNewServersEH;
        private TFEventHandler<IEnumerable<IServerProvider>> m_OnPreRemoveServersEH;
        private NameSpace m_Session;
        private Dictionary<Uri, OlServerProviderWrapper> m_serversMAP;
        private readonly object m_syncNewServers;
        private readonly object m_syncPreRemoveServers;
        private TeamFoundationDataProvider m_tfDataProvider;

        // Events
        public event TFEventHandler<IEnumerable<IServerProvider>> NewServers
        {
            add
            {
                lock (this.m_syncNewServers)
                {
                    this.m_OnNewServersEH = (TFEventHandler<IEnumerable<IServerProvider>>)Delegate.Combine(this.m_OnNewServersEH, value);
                }
            }
            remove
            {
                lock (this.m_syncNewServers)
                {
                    this.m_OnNewServersEH = (TFEventHandler<IEnumerable<IServerProvider>>)Delegate.Remove(this.m_OnNewServersEH, value);
                }
            }
        }

        public event TFEventHandler<IEnumerable<IServerProvider>> PreRemoveServers
        {
            add
            {
                lock (this.m_syncPreRemoveServers)
                {
                    this.m_OnPreRemoveServersEH = (TFEventHandler<IEnumerable<IServerProvider>>)Delegate.Combine(this.m_OnPreRemoveServersEH, value);
                }
            }
            remove
            {
                lock (this.m_syncPreRemoveServers)
                {
                    this.m_OnPreRemoveServersEH = (TFEventHandler<IEnumerable<IServerProvider>>)Delegate.Remove(this.m_OnPreRemoveServersEH, value);
                }
            }
        }

        // Methods
        private ExtentionDataProvider()
        {
            this.m_tfDataProvider = null;
            this.m_olDataProvider = null;
            this.m_serversMAP = new Dictionary<Uri, OlServerProviderWrapper>();
            this.m_OnNewServersEH = null;
            this.m_syncNewServers = new object();
            this.m_OnPreRemoveServersEH = null;
            this.m_syncPreRemoveServers = new object();
        }

        public ExtentionDataProvider(TeamFoundationDataProvider tfDataProvider, OutlookDataProvider olDataProvider, NameSpace session)
            : this()
        {
            this.TFDataProvider = tfDataProvider;
            this.OlDataProvider = olDataProvider;
            this.m_Session = session;
        }

        public IServerProvider GetServer(string uri)
        {
            return this.GetServer(new Uri(uri));
        }

        public IServerProvider GetServer(Uri uri)
        {
            IServerProvider provider = null;
            lock (this.m_serversMAP)
            {
                if (this.m_serversMAP.ContainsKey(uri))
                {
                    provider = this.m_serversMAP[uri];
                }
            }
            return provider;
        }

        private void OnDeleteServers(object sender, IEnumerable<ServerProvider> servers)
        {
            List<IServerProvider> list = new List<IServerProvider>();
            lock (this.m_serversMAP)
            {
                foreach (ServerProvider provider in servers)
                {
                    if (this.m_serversMAP.ContainsKey(provider.ServerUri))
                    {
                        OlServerProviderWrapper item = this.m_serversMAP[provider.ServerUri];
                        this.m_serversMAP.Remove(provider.ServerUri);
                        list.Add(item);
                    }
                }
            }
            this.RaisePreRemoveServers(list);
        }

        private void OnNewServers(object sender, IEnumerable<ServerProvider> servers)
        {
            List<IServerProvider> list = new List<IServerProvider>();
            lock (this.m_serversMAP)
            {
                foreach (ServerProvider provider in servers)
                {
                    OlServerProviderWrapper wrapper = new OlServerProviderWrapper(provider);
                    wrapper.InitFolder(this.AppMAPIFolderRoot);
                    this.m_serversMAP.Add(wrapper.ServerUri, wrapper);
                    list.Add(wrapper);
                }
            }
            this.RaiseNewServers(list);
        }

        private void RaiseNewServers(IEnumerable<IServerProvider> servers)
        {
            CommonGlobal.RaiseEventHandler(this.m_OnNewServersEH, new object[] { this, servers }, this.m_syncNewServers);
        }

        private void RaisePreRemoveServers(IEnumerable<IServerProvider> servers)
        {
            CommonGlobal.RaiseEventHandler(this.m_OnPreRemoveServersEH, new object[] { this, servers }, this.m_syncPreRemoveServers);
        }

        public void Update()
        {
            foreach (IServerProvider provider in this.Servers)
            {
                try
                {
                    provider.Update();
                }
                catch (Exception exception)
                {
                    Debug.WriteLine(exception.ToString());
                }
            }
        }

        // Properties
        public Application Application
        {
            get
            {
                return this.OlDataProvider.Application;
            }
        }

        public MAPIFolder AppMAPIFolderRoot
        {
            get
            {
                return this.OlDataProvider.AppMAPIFolderRoot;
            }
        }

        public CommandBarPopup AppMenuItemRoot
        {
            get
            {
                return this.OlDataProvider.AppMenuItemRoot;
            }
        }

        public string AppStoreFolderPath
        {
            get
            {
                return this.OlDataProvider.AppStoreFolderPath;
            }
        }

        public string AppStoreID
        {
            get
            {
                return this.OlDataProvider.AppStoreID;
            }
        }

        public IntPtr Hwnd
        {
            get
            {
                return Connect.Hwnd;
            }
        }

        public LicenceType LicenceType
        {
            get
            {
                return ApplicationGlobal.LicenceDataProvider.LicenceType;
            }
            set
            {
                ApplicationGlobal.LicenceDataProvider.LicenceType = value;
            }
        }

        protected OutlookDataProvider OlDataProvider
        {
            get
            {
                return this.m_olDataProvider;
            }
            private set
            {
                if (value == null)
                {
                    throw new ArgumentException();
                }
                this.m_olDataProvider = value;
            }
        }

        public IEnumerable<MAPIFolder> OlStandardFolders
        {
            get
            {
                return new List<MAPIFolder>();
            }
        }

        public NameSpace Session
        {
            get
            {
                return this.m_Session;
            }
        }

        public IRibbonUI RibbonUI
        {
            get
            {
                return ApplicationGlobal.RibbonUI;
            }
        }

        private IStream threadStream;
        public IStream Stream
        {
            get { return threadStream; }
            set { threadStream = value; }
        }

        public IEnumerable<IServerProvider> Servers
        {
            get
            {
                lock (this.m_serversMAP)
                {
                    foreach (OlServerProviderWrapper item in m_serversMAP.Values)
                        yield return item;
                }
            }
        }

        protected TeamFoundationDataProvider TFDataProvider
        {
            get
            {
                return this.m_tfDataProvider;
            }
            private set
            {
                if (value == null)
                {
                    throw new ArgumentException();
                }
                this.m_tfDataProvider = value;
                this.m_tfDataProvider.NewServers += new TFEventHandler<IEnumerable<ServerProvider>>(this.OnNewServers);
                this.m_tfDataProvider.PreRemoveServers += new TFEventHandler<IEnumerable<ServerProvider>>(this.OnDeleteServers);
            }
        }
    }

    /*
    internal class ExtentionDataProvider : IExtentionDataProvider
    {
        protected TeamFoundationDataProvider TFDataProvider
        {
            get { return this.m_tfDataProvider; }
            private set
            {
                if( value == null ) throw new ArgumentException();
                this.m_tfDataProvider = value;

                this.m_tfDataProvider.NewServers += new TFEventHandler<IEnumerable<ServerProvider>>( OnNewServers );
                this.m_tfDataProvider.PreRemoveServers += new TFEventHandler<IEnumerable<ServerProvider>>( OnDeleteServers );
            }
        }
        private TeamFoundationDataProvider m_tfDataProvider = null;

        protected OutlookDataProvider OlDataProvider
        {
            get { return this.m_olDataProvider; }
            private set
            {
                if( value == null ) throw new ArgumentException();
                this.m_olDataProvider = value;
            }
        }
        private OutlookDataProvider m_olDataProvider = null;

        private ExtentionDataProvider()
        { }
        public ExtentionDataProvider( TeamFoundationDataProvider tfDataProvider, OutlookDataProvider olDataProvider ) : this()
        {
            this.TFDataProvider = tfDataProvider;
            this.OlDataProvider = olDataProvider;
        }

        private void OnNewServers( object sender, IEnumerable<ServerProvider> servers )
        {
            List<IServerProvider> additems = new List<IServerProvider>();

            lock( this.m_serversMAP )
            {
                foreach( ServerProvider item in servers )
                {
                    OlServerProviderWrapper server = new OlServerProviderWrapper( item );
                    server.InitFolder(this.AppMAPIFolderRoot);

                    this.m_serversMAP.Add( server.ServerUri, server );
                    additems.Add( server );
                }
            }

            this.RaiseNewServers( additems );
        }
        private void OnDeleteServers( object sender, IEnumerable<ServerProvider> servers )
        {
            List<IServerProvider> deleteItems = new List<IServerProvider>();

            lock( this.m_serversMAP )
            {
                foreach( ServerProvider item in servers )
                {
                    if( !this.m_serversMAP.ContainsKey( item.ServerUri ) )
                        continue;

                    OlServerProviderWrapper wrapper = this.m_serversMAP[item.ServerUri];
                    this.m_serversMAP.Remove( item.ServerUri );
                    deleteItems.Add( wrapper );
                }
            }

            this.RaisePreRemoveServers( deleteItems );

            //delete folders from outlook
            foreach( OlServerProviderWrapper item in deleteItems )
                item.Delete();

        }

        #region ITeamFoundationDataProvider Members

        public IEnumerable<IServerProvider> Servers
        {
            get 
            {
                lock( this.m_serversMAP )
                {
                    foreach( OlServerProviderWrapper item in m_serversMAP.Values )
                        yield return item;
                }
            }
        }
        private Dictionary<Uri, OlServerProviderWrapper> m_serversMAP = new Dictionary<Uri, OlServerProviderWrapper>();

        public IServerProvider GetServer( string uri )
        {
            return this.GetServer( new Uri(uri) );
        }
        public IServerProvider GetServer( Uri uri )
        {
            IServerProvider provider = null;

            lock( this.m_serversMAP )
            {
                if( this.m_serversMAP.ContainsKey(uri) )
                    provider = this.m_serversMAP[uri];
            }

            return provider;
        }

        #region event NewServers

        public event TFEventHandler<IEnumerable<IServerProvider>> NewServers
        {
            add { lock( this.m_syncNewServers ) { this.m_OnNewServersEH += value; } }
            remove { lock( this.m_syncNewServers ) { this.m_OnNewServersEH -= value; } }
        }
        private TFEventHandler<IEnumerable<IServerProvider>> m_OnNewServersEH = null;

        private readonly object m_syncNewServers = new object();

        private void RaiseNewServers( IEnumerable<IServerProvider> servers )
        {
            CommonGlobal.RaiseEventHandler( this.m_OnNewServersEH, new object[] { this, servers }, m_syncNewServers );
        }

        #endregion event NewServers

        #region event PreRemove Servers

        public event TFEventHandler<IEnumerable<IServerProvider>> PreRemoveServers
        {
            add { lock( this.m_syncPreRemoveServers ) { this.m_OnPreRemoveServersEH += value; } }
            remove { lock( this.m_syncPreRemoveServers ) { this.m_OnPreRemoveServersEH -= value; } }
        }
        private TFEventHandler<IEnumerable<IServerProvider>> m_OnPreRemoveServersEH = null;

        private readonly object m_syncPreRemoveServers = new object();

        private void RaisePreRemoveServers( IEnumerable<IServerProvider> servers )
        {
            CommonGlobal.RaiseEventHandler( this.m_OnPreRemoveServersEH, new object[] { this, servers }, m_syncPreRemoveServers );
        }

        #endregion event DeteteServers

        public void Update()
        {
            foreach( IServerProvider item in this.Servers )
            {
                try
                {
                    item.Update();
                }
                catch( System.Exception ex )
                {
                    Debug.WriteLine( ex.ToString() );
                }
            }
        }

        #endregion

        #region IExtentionDataProvider Members

        public Microsoft.Office.Interop.Outlook.Application Application
        {
            get { return this.OlDataProvider.Application; }
        }

        public CommandBarPopup AppMenuItemRoot
        {
            get { return this.OlDataProvider.AppMenuItemRoot; }
        }

        public MAPIFolder AppMAPIFolderRoot
        {
            get { return this.OlDataProvider.AppMAPIFolderRoot; }
        }

        public IEnumerable<MAPIFolder> OlStandardFolders
        {
            get 
            {
                return new List<MAPIFolder>();
            }
        }

        public string AppStoreID
        {
            get { return this.OlDataProvider.AppStoreID; }
        }

        public string AppStoreFolderPath
        {
            get { return this.OlDataProvider.AppStoreFolderPath; }
        }

        /// <summary>
        /// Outlook window handle
        /// </summary>
        public IntPtr Hwnd
        {
            get { return Connect.Hwnd; }
        }

        #endregion
    }
     * */
}
